package mx.itesm.twritter.server.parser;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import winterwell.jtwitter.Status;

public class ParsedTweetRegex {

	/**--------------------------------------------------C A M B I A R  R U T A ! ! ----------------------------------------------------------------- **/
	private static final String rutaCalles = "../src/mx/itesm/twritter/server/parser/calles.txt"; // <--------
	/**--------------------------------------------------C A M B I A R  R U T A ! ! ----------------------------------------------------------------- **/
	
	/** Tweet Traffic report */
	private String tweet;

	/** Velocity of the street.
	 * Ex: lento, constante, asentamientos */
	private String streetVelString;

	/** Velocity of the street in km/h 
	 * Ex: 20, 50, 100 */
	private int streetVel;
	
	/** Name of the street the tweet's traffic report is informing of */
	private String streetName;

	/** Name of the street from where the tweet's traffic report starts */
	private String streetFrom;
	
	/** Name of the street to where the tweet's traffic report ends */
	private String streetTo;
	
	/** Id of the traffic tweet */
	private String tweetId;
	
	/** Flag to know if the tweet can be parsed with the initial desdeREX */
	private boolean isDesdeREX;
	
	/** Flag to know if the tweet can be parsed with the initial isHastaREX */
	private boolean isHastaREX;
	
	/** To create a regex */
	private Pattern p;

	/** To find the regex created with the pattern */
	private Matcher m;

///////////////////////////////////////////////////////////////////
	
	/** Parses the tweet and add them to the parsedTweetList */
	private void parseTweet() {
		
		// Variables locales
		final int flags = Pattern.CASE_INSENSITIVE | Pattern.COMMENTS;
		
		String tweet;
		tweet = cleanTweet(this.tweet);
		// agrego un punto al inicio y al final para saber como inicia y como termina.
		tweet += ". " + tweet;
		tweet += ".";
		
		// creo mis palabras clave		
		String infoREX = "(.*?)";
		String velREX = 
			"(" +
			"(?:INTENSA.(?:LA)?|LIGERA)?\\s?CARGA\\s?(?:ABUNDANTE.CON.AVANCE.CONSTANTE)?|" +
			"(?:LIGEROS|LARGOS)?.ASENTAMIENTOS?|" +
			"ABUNDANTE|ACEPTABLE|" +
			"RAPIDO|" +
			"MARAVILLA|" +
			"INCREMENTO.NOTABLE|"+
			"V\\s?UELTA.DE.RUEDA|" +
			"COMPLICAD[OA]|" +
			"(?:MUY)?.(?:LENT[OA]|PESADO)|" +
			"(?:^|\\s)B[UI]EN[A]?\\s|" +
			"NO.TE.VAS.A.DETENER|" +
			"CIRCULAR.SIN.PROBLEMAS|" +
			"LARGAS.FILAS|" +
			"FAVORABLE|" +
			"INCONVENIENTES|" +
			"CERRAD[OA]S?|" +
			"CONSTANTE|" +
			"CONSTRUCCION|" +
			"CORTE|" +
			"DETENIDO|" +
			"OBRAS|ACCIDENTE|CHOQUE|" +
			"(?:PERCANCE|INCIDENTE).(?:VIAL|VEHICULAR)|" +
			"CIERRE|" +
			"REDUCCION|" +
			"IMPOSIBLE|" +
			"FLUIDO|" +
			"MUCHO.TRAFICO|" +
			")";
		String enREX = "(\\sen\\s|^en\\s|\\sal?\\s)";
		String desdeREX = "(?:desde|(?:a.partir|procedente|a.la.altura).(?:de)?|pasando)";
		String hastaREX = "(?:\\sy?.?ha?sta.(?:por.lo.menos)?|(?:y.para.llegar)?.hacia|y?.(?:con|en)?.direccion.a\\s)";
		String finREX = "(?:[/.])";

	   // checo si el tweet no tiene 'de' como separador
		p = Pattern.compile (infoREX + desdeREX + infoREX);
		m = p.matcher(tweet);
		isDesdeREX = m.find();
		
		// pending....
		if (!isDesdeREX) {
			desdeREX = "(?:\\sentr?e)";
			p = Pattern.compile (infoREX + desdeREX + infoREX);
			m = p.matcher(tweet);
			if (!m.find()) {
				desdeREX = "(?:\\sde\\s|\\sdel\\s)";
			}
			
		}
		
		// checo si el tweet no tiene 'a' como separador
		p = Pattern.compile (infoREX + hastaREX + infoREX);
		m = p.matcher(tweet);
		isHastaREX = m.find();
		
		// pending....
		if (!isHastaREX) {
			hastaREX = "(?:\\s[ye]\\s|\\sal?\\s)";
		}
		
		parseTweet(infoREX, enREX, velREX, desdeREX, hastaREX, finREX, flags, tweet);

	}
	
	private void parseTweet(String infoREX, String enREX, String velREX,
			String desdeREX, String hastaREX, String finREX, int flags, String tweet) {
		p = Pattern.compile(
				infoREX + 
				velREX + infoREX + 
				desdeREX + infoREX + 
				hastaREX + infoREX +
				finREX
				, flags);
     
		m = p.matcher(tweet);

		if (m.find()) {	
			///////////////////////////////////////////////////////////////////////////////////////////////////
			streetVelString = m.group(2);
			streetVelString = cleanTweet(streetVelString);
			streetVelString = streetVelString.toLowerCase();
			///////////////////////////////////////////////////////////////////////////////////////////////////
			// busco el nombre de la calle despues de la velocidad
			streetName = m.group(3);
			// si hay palabras clave, que sea a partir de ahi
			streetName += ".";
			
			p = Pattern.compile(
						enREX + infoREX +
						finREX
						, flags);
			Matcher m3;
			m3 = p.matcher(streetName);
			if (m3.find()) {
				streetName = m3.group(2);
			}
			
			// si salio peor, mejor regresa como estabas
			if (!isStreet(streetName))
				streetName = m.group(3);
			
			// al nombre de la calle le quito palabras y espacios
			streetName = eraseWords(streetName);
			streetName = cleanTweet(streetName);
				
			// si lo que obtuve no parece ser un nombre de calle 
			// intento en el grupo antes de la palabra clave de vel
			
			if (!isStreet(streetName)){
				streetName = m.group(1);
				
				// si hay palabras clave, que sea a partir de ahi
				streetName += ".";
				m3 = p.matcher(streetName);
				if (m3.find()) {					
					streetName = m3.group(2);
				}
				
				// si salio peor, mejor regresa como estabas
				if (!isStreet(streetName))
					streetName = m.group(1);
				
				streetName = eraseWords(streetName);
				streetName = cleanTweet(streetName);
				
				
			}
			streetName = streetName.toLowerCase();
			StringMatchingNonExact StreetNameCorrected = 
					new StringMatchingNonExact(rutaCalles, streetName);
			streetName = StreetNameCorrected.getStreet();
					
			///////////////////////////////////////////////////////////////////////////////////////////////////
			int groupStreetFrom = 4;
			
			streetFrom = m.group(groupStreetFrom);
			streetFrom = eraseWords(streetFrom);
			streetFrom = cleanTweet(streetFrom);
			streetFrom = streetFrom.toLowerCase();
			StringMatchingNonExact StreetFromCorrected = 
					new StringMatchingNonExact(rutaCalles, streetFrom);
			streetFrom = StreetFromCorrected.getStreet();
			///////////////////////////////////////////////////////////////////////////////////////////////////
			int groupDesdeREX = 5;
			
			streetTo = m.group(groupDesdeREX);
			
			streetTo = eraseWords(streetTo);
			streetTo = cleanTweet(streetTo);
			streetTo = streetTo.toLowerCase();
			StringMatchingNonExact StreetToCorrected = 
					new StringMatchingNonExact(rutaCalles, streetTo);
			streetTo = StreetToCorrected.getStreet();
			///////////////////////////////////////////////////////////////////////////////////////////////////
		}
		
		
	}

	/** Looks for proper names */
	private boolean isStreet (String cadena) {
		Pattern linkPattern = Pattern.compile("\\s[A-Z][a-z]*|^[A-Z][a-z]*");
		Matcher m;
		
		m = linkPattern.matcher(cadena);
	
		return m.find();
	}
	
	/** 
	 * Erases the trash from the tweet
	 * @param cadena sentence to be cleaned
	 * @return a sentence without users, leading and traling whitespaces, 
	 * acronyms, links, accents, and others characters that are neither 
	 * letters, numbers nor whitespaces 
	 */
	public String cleanTweet(String cadena) {
		
		String cleanedTweet = cadena;
		// erase Users
		cleanedTweet = cleanedTweet.replaceAll("@\\w*", "");
		// erase hrs.
		cleanedTweet = cleanedTweet.replaceAll("(^.{4,9}|)\\d\\d:\\d\\d", "");
		// trim leading and trailing whitespaces
		cleanedTweet = cleanedTweet.replaceAll("^\\s+|\\s+$", "");
		// erase Acronyms
		cleanedTweet = cleanedTweet.replaceAll("[A-Z][A-Z]+", "");
		// erase acute;
		cleanedTweet = cleanedTweet.replaceAll("acute;", "");
		// creates a space for nbsp;
		cleanedTweet = cleanedTweet.replaceAll("nbsp;", " ");
		// erase .: (vialDF)
		cleanedTweet = cleanedTweet.replaceAll(":.*", "");
		// erase characters that are neither letters, numbers nor whitespaces.
		cleanedTweet = cleanedTweet.replaceAll("[^\\p{L}\\p{N}\\s]|\n", "");
		// erase accents in vowels
		cleanedTweet = cleanedTweet.replaceAll("[á|à|ä|â]", "a");
		cleanedTweet = cleanedTweet.replaceAll("[Á|Ä]", "A");
		cleanedTweet = cleanedTweet.replaceAll("[é|è|ë|ê]", "e");
		cleanedTweet = cleanedTweet.replaceAll("[É|Ë]", "E");
		cleanedTweet = cleanedTweet.replaceAll("[í|ì|ï|î]", "i");
		cleanedTweet = cleanedTweet.replaceAll("[Í|ì|Ï|î]", "I");
		cleanedTweet = cleanedTweet.replaceAll("[ó|ò|ö|ô]", "o");
		cleanedTweet = cleanedTweet.replaceAll("[Ó|Ö]", "O");
		cleanedTweet = cleanedTweet.replaceAll("[ú|ù|ü|û]", "u");
		//System.out.println(cleanedTweet);
		return cleanedTweet;
	}

	/** 
	 * Erases all the words from the string which are
	 * not proper names.
	 * @param cadena sentence to be cleaned
	 * @returns sentence with just Street names.
	 */
	private String eraseWords(String cadena) {
		String cleanedTweet = cadena.replaceAll("^[a-z]+|\\s[a-z]+", "");
		return cleanedTweet;
	}
	
	@Override
	public String toString() {
		String parsedTweet = "" 
			+ "Tweet:\t" + tweet + "\n" 
			+ "Id:\t" + tweetId + "\n"
			+ "Vel:\t" + streetVelString + "\n" 
			+ "Street:\t" + streetName + "\n"
			+ "From:\t" + streetFrom + "\n" 
			+ "To:\t" + streetTo + "\n"
		;
		return parsedTweet;

	}
	
	/** Method to know if the tweet was parsed correctly */
	public boolean isParsed() {
		if (streetVelString != null
			&& streetName != null
			&& streetFrom != null
			&& streetTo != null)
				return true;
		
		return false;
	}
	
///////////////////////////////////////////////////////////////////
	
	/* Getters and setters
	 * Self explanatory*/
	public String getTweet() {
		return tweet;
	}

	public String getStreetVelString() {
		return streetVelString;
	}

	public int getStreetVel() {
		return streetVel;
	}

	public String getStreetName() {
		return streetName;
	}

	public String getStreetFrom() {
		return streetFrom;
	}

	public String getStreetTo() {
		return streetTo;
	}

	public String getTweetId() {
		return tweetId;
	}

///////////////////////////////////////////////////////////////////
			
	/** Constructor of the class
	 * @param tweet Tweet to be parsed 
	 */
	public ParsedTweetRegex(Status tweet) {
		this.tweet = tweet.toString();
		this.tweetId = tweet.getId().toString();
		parseTweet();
	}
	
	public ParsedTweetRegex(String tweet, String id) {
		this.tweet = tweet;
		this.tweetId = id;
		parseTweet();
	}

}
